package org.andao.core.utils;

import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.Assert;

/**
 * 常用Bean工具集. <p>
 * 该类继承apache BeanUtils，可以自行扩展.<p>
 * @author Marco.hu(hzg139@163.com)
 */
public class ExBeanUtils extends BeanUtils{

	protected static Logger logger = LoggerFactory.getLogger(BeanUtils.class);
	
	/**
	 * 获取对象属性.
	 * 强制获取，无须通过get方法.
	 * @param object 对象
	 * @param fieldName 属性
	 * @return
	 * @throws NoSuchFieldException
	 */
	public static Object getFieldValue(Object object, String fieldName) throws NoSuchFieldException {
		Field field = getDeclaredField(object, fieldName);		

		Object result = null;
		if (null != field && !field.isAccessible()) {
			field.setAccessible(true);
			try {
				result = field.get(object);
			} catch (IllegalAccessException e) {
				logger.error("不可能抛出的异常{}", e.getMessage());
			}
		}
		
		return result;
	}
	
	/**
	 * 设置对象属性值.
	 * 强制设置，无须通过set方法.
	 * @param object
	 * @param fieldName
	 * @param value
	 * @throws NoSuchFieldException
	 */
	public static void setFieldValue(Object object, String fieldName, Object value) throws NoSuchFieldException {
		Field field = getDeclaredField(object, fieldName);
		if (null != field && !field.isAccessible()) {
			field.setAccessible(true);
		}
		try {
			field.set(object, value);
		} catch (IllegalAccessException e) {
			logger.error("不可能抛出的异常:{}", e.getMessage());
		}
	}

	/**
	 * 循环向上转型,获取对象的DeclaredField.
	 * @param object
	 * @param fieldName
	 * @return
	 * @see #getDeclaredField(Class clazz, String fieldName)
	 * @throws NoSuchFieldException
	 */
	public static Field getDeclaredField(Object object, String fieldName) throws NoSuchFieldException {
		Assert.notNull(object);	
		return getDeclaredField(object.getClass(), fieldName);
	}
	
	/**
	 * 获取实体属性的注解
	 * @param object
	 * @param fieldName
	 * @return
	 * @throws NoSuchFieldException
	 */
	public static Annotation[] getAnnotation(Object object, String fieldName) throws NoSuchFieldException {
		return getDeclaredField(object.getClass(), fieldName).getAnnotations();
	}

	/**
	 * 循环向上转型,获取类的DeclaredField.
	 * @param clazz
	 * @param fieldName
	 * @return
	 * @throws NoSuchFieldException
	 */	
	public static Field getDeclaredField(Class clazz, String fieldName) throws NoSuchFieldException {
		Assert.notNull(clazz);
		Assert.hasText(fieldName);
		if("serialVersionUID".equals(fieldName)){//suid排除
			return null;
		}
		for (Class superClass = clazz; superClass != Object.class; superClass = superClass.getSuperclass()) {
			try {
				return superClass.getDeclaredField(fieldName);
			} catch (NoSuchFieldException e) {
				// Field不在当前类定义,继续向上转型
			}
		}
		throw new NoSuchFieldException("No such field: " + clazz.getName() + '.' + fieldName);
	}
	
	/**
	 * 对象间属性的copy
	 * @param dest 目标对象
	 * @param orig 源对象
	 */
	public static synchronized void copyProperties(Object dest, Object orig){
		try {			
			copyBeans(orig,dest);
		} catch (Exception e1) {			
			logger.error("属性拷贝时抛出的异常:{}", e1.getMessage());
		} 
	}
	
	/**
	 * Copy指定属性
	 * @param oldObj
	 * @param newObj
	 * @param propertyArray
	 * @return
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 * @throws NoSuchMethodException
	 */
	public static Object copyBeans(Object oldObj, Object newObj,String[][] propertyArray) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
		newObj = copyBeans(oldObj, newObj);  
		 for (int i = 0; i < propertyArray.length; i++) {  
		   for (int t = 0; t < propertyArray[i].length; t++) {  
			 if (propertyArray[i].length < 2)  
				 return newObj;  
			 if (propertyArray[i][t] == null)  
				 return newObj;  
			 }  
			   
			 try {  
				 Object indate = PropertyUtils.getNestedProperty(oldObj,propertyArray[i][0]);  
				 if (indate instanceof java.util.Date) {  
					 indate = new java.sql.Date(((java.util.Date) indate).getTime());  
				 }  
				 	PropertyUtils.setNestedProperty(newObj, propertyArray[i][1],indate);  
				 } catch (IllegalAccessException e) {  
					 e.printStackTrace();  
				 } catch (InvocationTargetException e) {  
					 e.printStackTrace();  
				 } catch (NoSuchMethodException e) {  
					 e.printStackTrace();  
				 }  
			 }  
			 return newObj;  
	}  
	
	/** 
	* 由旧的Bean,copy数据到新的Bean中,返回新的Bean 
	*  
	* @param oldObj 旧的Bean 
	* @param newObj 新的Bean 
	* @return Object 返回新的JavaBean 
	 * @throws NoSuchMethodException 
	 * @throws InvocationTargetException 
	 * @throws IllegalAccessException 
	*/  
	public static Object copyBeans(Object oldObj, Object newObj) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {  
		 PropertyDescriptor[] oldPds = PropertyUtils .getPropertyDescriptors(oldObj);  
		 PropertyDescriptor[] newPds = PropertyUtils .getPropertyDescriptors(newObj);  
		 String[] propertys = new String[250];  
		 int ss = 0;  
		 for (int i = 0; i < oldPds.length; i++) {  
			 PropertyDescriptor oldPd = oldPds[i];  
			 for (int t = 0; t < newPds.length; t++) {  
				 PropertyDescriptor newPd = newPds[t];
				 if(null == newPd.getWriteMethod()) continue;
				 if ((oldPd.getDisplayName().equals(newPd.getDisplayName())) && (!newPd.getDisplayName().equals("class"))) {  
					 propertys[ss] = oldPd.getDisplayName(); 					
					 ss = ss + 1;  
					 break;  
				 }  
			 }  
		 }  
		   
		 for (int i = 0; i < propertys.length; i++) {  
			 if (propertys[i] == null) 	 return newObj;  			 
			 	 //获取值				 
				 Object indate = PropertyUtils.getNestedProperty(oldObj,propertys[i]);		
				 if(null == indate) continue;
				
				// 处理日期  
				 if (indate instanceof java.util.Date) {  
					 indate = new java.sql.Date(((java.util.Date) indate).getTime());  
				 }  
								 
				  if(indate instanceof Collection){
					 if(null != indate){
						 Collection c = (Collection)indate;
							if(c.isEmpty() || c.size()<1){
								continue;
							}
					 }
					
				 }				
				 PropertyUtils.setNestedProperty(newObj, propertys[i], indate);		
				  				 
				  
		 }  
		 return newObj;  
	 } 
	
	/**
	 * 将bean 转换为map
	 * @param <T>
	 * @param t
	 * @return
	 */
	 public static <T> Map<String,Object> convertBeanToMap(T t){  
	     Map<String,Object> map = new HashMap<String, Object>();  
	          
	     Class cls=t.getClass();  
	     Field[] fieldlist = cls.getDeclaredFields();  
	     for(int i=0;i<fieldlist.length;i++){ //遍历bean属性 
	          Field f=fieldlist[i];  
	          String name=f.getName();  
	          
	          Class<?> cs=f.getType();  
	          try {  
	              String methodNme = changeStrToGetMethodNames(name);  
	              Method meth = null;  
	              Method[] mds = cls.getDeclaredMethods();  
	                for(int j=0;j<mds.length;j++){  
	                    if(mds[j].getName().equals(methodNme)){  
	                         meth = cls.getMethod(methodNme);  //使用get方法获取值
	                         Object rtcs= meth.invoke(t, null);  
	                         if(null != rtcs)
	                         map.put(name, rtcs);  
	                        break;  
	                    }  
	                }  
	            if(meth==null){  
	                logger.debug("在"+t.getClass().getName()+"中没有找到"+methodNme+"方法");  
	            }  
	                  
	            } catch (SecurityException e) {  
	              
	            } catch (NoSuchMethodException e) {  
	              
	            } catch (IllegalArgumentException e) {  
	               
	            } catch (IllegalAccessException e) {  
	               
	            } catch (InvocationTargetException e) {  
	              
	            }  
	        }  
	        return map;  
	 }  
	 
	 //转换属性为get方法
	 private static String changeStrToGetMethodNames(String str){  
	    if(ExStringUtils.isBlank(str)) return null;  
	       char firstChar=str.toCharArray()[0];  
	       String upstr=String.valueOf(firstChar).toUpperCase();  
	       return "get"+upstr+str.substring(1);  
	 }  
	      
}
